package org.kenewstar.file.service.impl;

import org.kenewstar.common.bean.pojo.MicroFile;
import org.kenewstar.common.bean.pojo.MicroFolder;
import org.kenewstar.common.bean.pojo.MicroShare;
import org.kenewstar.common.constant.CommonConstant;
import org.kenewstar.common.utils.CommonResult;
import org.kenewstar.common.utils.CommonUtil;
import org.kenewstar.common.utils.DateUtil;
import org.kenewstar.file.dto.*;
import org.kenewstar.file.mapper.FileMapper;
import org.kenewstar.file.mapper.FolderMapper;
import org.kenewstar.file.mapper.ShareMapper;
import org.kenewstar.file.service.ShareService;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xinke.huang@hand-china.com
 * @version 1.0
 * @date 2021/3/10
 */
@Service
public class ShareServiceImpl implements ShareService {

    @Resource
    private ShareMapper shareMapper;
    @Resource
    private FileMapper fileMapper;
    @Resource
    private FolderMapper folderMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ShareUrlAndCodeDto createShare(ShareFileParamDto dto, Integer uid) {
        MicroShare share = new MicroShare();
        share.setShareName(dto.getShareName());
        share.setShareValidTime(dto.getValidTime());
        share.setUserId(uid);
        share.setShareUrl(CommonUtil.generateShareUrlSuffix());
        share.setShareCode(CommonUtil.generateShareCode(4));
        share.setShareFileList(dto.getFileListJson());
        // 执行插入
        shareMapper.insertShare(share);
        // 创建返回对象
        ShareUrlAndCodeDto urlAndCode = new ShareUrlAndCodeDto();
        urlAndCode.setUrl(CommonConstant.SHARE_URL_PREFIX+share.getShareUrl());
        urlAndCode.setCode(share.getShareCode());
        return urlAndCode;
    }

    @Override
    public List<ShareFileUrlDto> queryAllShare(Integer uid) {
        // 查询所有数据
        List<MicroShare> shares = shareMapper.selectAllShare(uid);
        // 构造返回对象
        List<ShareFileUrlDto> dtoList = new ArrayList<>(shares.size());
        ShareFileUrlDto shareFileUrlDto;
        // 解析所有数据
        for (MicroShare share:shares){
            shareFileUrlDto = new ShareFileUrlDto();
            shareFileUrlDto.setId(share.getId());
            shareFileUrlDto.setShareName(share.getShareName());
            shareFileUrlDto.setShareUrl(CommonConstant.SHARE_URL_PREFIX + share.getShareUrl());
            shareFileUrlDto.setShareCode(share.getShareCode());
            shareFileUrlDto.setShareTime(share.getShareTime());
            shareFileUrlDto.setUserId(share.getUserId());
            // 校验分享文件是否被删除
            String fileListJson = share.getShareFileList();

            Date shareTime = share.getShareTime();
            // 判断分享是否过期
            boolean isPass = DateUtil.compareCurrentDatePass(shareTime, share.getShareValidTime());
            shareFileUrlDto.setValid(isPass?"N":"Y");
            // 获取有效时间
            shareFileUrlDto.setValidTime(isPass ? "分享已失效" : DateUtil.getCurrentDateValidTime(shareTime,share.getShareValidTime()));

            try {
                List<FileShareDto> list = CommonUtil.json2List(fileListJson, FileShareDto.class);
                long count = validateFileDeleted(list);
                if (count == 0) {
                    shareFileUrlDto.setValid("N");
                    shareFileUrlDto.setValidTime("分享已失效");
                } else {
                    shareFileUrlDto.setValid("Y");
                }
            } catch (Exception e) {
                // 无效
                shareFileUrlDto.setValid("N");
            }
            dtoList.add(shareFileUrlDto);
        }
        return dtoList;
    }

    @Override
    public long validateFileDeleted(List<FileShareDto> list) {
        List<FileShareDto> files = new ArrayList<>();
        List<FileShareDto> folders = new ArrayList<>();
        list.forEach((obj)->{
            if (Objects.equals(obj.getType(),CommonConstant.FILE)){
                files.add(obj);
            } else {
                folders.add(obj);
            }
        });
        long count = 0;
        if (files.size() != 0){
            count += fileMapper.selectCountNotDeleted(files);
        }
        if (folders.size() != 0){
            count +=  folderMapper.selectCountNotDeleted(folders);
        }
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteShare(List<Long> ids) {
        if (ids.size() != 0){
            return shareMapper.batchDeleteShare(ids);
        }
        return 0;
    }

    @Override
    public MicroShare extractFile(String url) {
        return shareMapper.selectShareByUrl(url);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult saveShareFilesAndFolders(List<MicroFile> files, List<MicroFolder> folders,
                                                 Map<Long, List<MicroFile>> filesMap,
                                                 Map<Long, List<MicroFolder>> foldersMap,
                                                 Integer userId) {
        // 获取事务状态
        TransactionStatus transactionStatus = TransactionAspectSupport.currentTransactionStatus();
        try {
            folders.forEach(folder -> {
                if (files.size() != 0) {
                    fileMapper.batchInsertFiles(files);
                }
                // 递归保存文件夹
                addFoldersAndFiles(folders, foldersMap, filesMap, userId);
            });
        } catch (DataAccessException e) {
            transactionStatus.setRollbackOnly();
            e.printStackTrace();
            return CommonResult.failed("存在相同文件名");
        }
        return CommonResult.success();
    }

    /**
     * 递归添加文件及文件夹
     * @param folders
     * @param foldersMap
     * @param filesMap
     */
    public void addFoldersAndFiles(List<MicroFolder> folders,
                                   Map<Long, List<MicroFolder>> foldersMap,
                                   Map<Long, List<MicroFile>> filesMap,
                                   Integer userId) {
        folders.forEach(folder -> {
            Long pid = folder.getId();
            folder.setUserId(userId);
            folderMapper.insertFolderAndGetKey(folder);
            // 获取当前插入文件夹的子文件夹
            List<MicroFolder> folderList = foldersMap.get(pid);
            List<MicroFolder> collectFolderList
                    = folderList.stream().peek(folder1 -> {
                        folder1.setParentFolderId(folder.getId());
                        folder1.setUserId(userId);
                    }).collect(Collectors.toList());
            // 获取当前文件夹下的子文件
            List<MicroFile> fileList = filesMap.get(pid);

            if (fileList.size() != 0) {
                List<MicroFile> collectFileList
                        = fileList.stream().peek(file -> file.setFolderId(folder.getId()))
                        .collect(Collectors.toList());
                // 批量插入文件
                fileMapper.batchInsertFiles(collectFileList);
            }
            addFoldersAndFiles(collectFolderList, foldersMap, filesMap, userId);

        });
    }
}
